/*
 *            DO YOU WHAT THE WANT TO PUBLIC LICENSE
 *
 * Everyone is permitted to copy and distribute verbatim or modified
 * copies of this license document, and changing it is allowed as long
 * as the name is changed.
 *
 *           DO YOU WHAT THE WANT TO PUBLIC LICENSE
 *  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 *
 * 0. You just DO WHAT YOU WANT TO DO.
 */

 /*
  * 原先使用sdl编写的贪吃蛇的ege移植版
  * 使用 ege 库
  * 使用 纯c语言编写
  */
#include <stdio.h>
// ege
#include <graphics.h>

 /* 长宽比例 */
#define WIDTH_BLOCK_COUNT 50
#define HIGHT_BLOCK_COUNT 40

/* 尺寸大小 */
#define BLOCK_SIZE 20

/* 窗体尺寸 */
#define WIN_WIDTH (BLOCK_SIZE * WIDTH_BLOCK_COUNT)
#define WIN_HIGHT (BLOCK_SIZE * HIGHT_BLOCK_COUNT)

/* 固定刷新时间 */
#define FIXED_TIME 30

/* 蛇的方向 */
enum snake_dir
{
    DIR_DOWN,  /* 下 */
    DIR_LEFT,  /* 左 */
    DIR_RIGHT, /* 右 */
    DIR_UP     /* 上 */
};

/* 当前方向 */
char dir;

/*
 *实体位置坐标
 */

 /* 蛇身实体(单一个体) */
typedef struct snk_body_entity
{
    /* 坐标 */
    int x;
    int y;

    /* 下一节身体 */
    struct snk_body_entity* next_body;

}snk_body_entity;

/* 食物实体 */
typedef struct food_entity
{
    /* 食物坐标 */
    int x;
    int y;

}food_entity;

/* 食物 */
food_entity* food = NULL;

/* 蛇头 */
snk_body_entity* snk_head = NULL;

/* 蛇体 */
snk_body_entity* snk_body = NULL;

/* 蛇体长度 */
unsigned snk_lenth;

/* 分数 */
unsigned score;

/* 是否暂停 */
bool isPause;

/* 绘制场景 */
void draw_scnen(void);
/* 初始化实体 */
void init_entity(void);
/* 蛇体移动 */
void snake_move(void);
/* 吃食物事件 */
void snake_eat_food(void);

void mainloop()
{
    for (; is_run(); delay_fps(FIXED_TIME))
    {
        // todo: 逻辑更新
        // 计算新坐标
        while (kbhit())
        {
            int key = getch();
            if (key == 'w' && dir != 0)
            {
                dir = 3;
            }
            else if (key == 's' && dir != 3)
            {
                dir = 0;
            }
            else if (key == 'a' && dir != 2)
            {
                dir = 1;
            }
            else if (key == 'd' && dir != 1)
            {
                dir = 2;
            }

            if (key == 'p')
            {
                isPause  = !isPause;
            }
        }
        if (isPause)
        {
            // 提示
            char tips[10];
            if (isPause)
            {
                sprintf(tips, "pause");
                setcolor(BLACK);
                outtextxy(WIN_WIDTH / 2, WIN_HIGHT / 2, tips);
            }
            continue;
        }
        snake_move();
        snake_eat_food();

        // todo: 图形更新
        // 清屏，重新在新的位置绘图图像
        cleardevice();
        draw_scnen();
        {
            // 画帧率文字
            char str[20];
            sprintf(str, "fps %.02f", getfps()); //调用getfps取得当前帧率
            setcolor(BLACK);
            outtextxy(0, 0, str);

            // 画分数
            char str_score[100];
            sprintf(str_score, "your score is :%d", score);
            setcolor(BLACK);
            outtextrect(WIN_WIDTH - 170, 0, 200, 100, str_score);
        }
    }
}

int main(void)
{
    setinitmode(INIT_ANIMATION);
    setcaption("greedy snake");
    // 图形初始化
    initgraph(WIN_WIDTH, WIN_HIGHT);
    // 随机数初始化，如果需要使用随机数的话
    randomize();
    // 初始化场景中的蛇与食物
    init_entity();
    // 程序主循环
    mainloop();
    // 关闭绘图设备
    closegraph();
}

// 为 ege 重新编写的
void draw_scnen(void)
{
    /*
     * 绘制背景
     */

     /* 背景颜色 */
    setbkcolor(WHITE);

    /*
     * 绘制蛇
     */

    snk_body_entity* body = snk_head;

    setfillcolor(RED);
    for (int i = 0; i < snk_lenth ; i++)
    {
        bar(body->x * BLOCK_SIZE - BLOCK_SIZE  / 2 //left
            , body->y * BLOCK_SIZE + BLOCK_SIZE  / 2 //top
            , body->x * BLOCK_SIZE + BLOCK_SIZE  / 2 //right
            , body->y * BLOCK_SIZE - BLOCK_SIZE  / 2 //bottom
            ); 
        body = body->next_body;
    }

    /*
     * 绘制食物
     */
    setfillcolor(BLUE);

    bar(food->x * BLOCK_SIZE - BLOCK_SIZE / 2 //left
        , food->y * BLOCK_SIZE + BLOCK_SIZE / 2 //top
        , food->x * BLOCK_SIZE + BLOCK_SIZE / 2 //right
        , food->y * BLOCK_SIZE - BLOCK_SIZE / 2); //bottom
}

void init_entity(void)
{
    /*
     *初始化蛇体
     */
    snk_lenth = 4;
    /* 方向 */
    dir = random(0) % 4;
    /* 分数 */
    score = 0;

    isPause = false;

    /* 当前开辟的位置 */
    snk_body_entity* temp;

    /* 初始化身体 */
    for (int i = 0; i < snk_lenth; i++)
    {
        temp = (snk_body_entity*)malloc(sizeof(snk_body_entity));
        /* 头部未初始化 */
        if (snk_head == NULL)
        {
            /* 蛇头初始化 */
            snk_head = temp;
            snk_head->x = random(0) % WIDTH_BLOCK_COUNT;
            snk_head->y = random(0) % HIGHT_BLOCK_COUNT;
        }
        else
        {
            /* 身体初始化 */
            snk_body->next_body = temp;
        }

        /* 给其赋值 */
        temp->next_body = NULL;

        temp->x = snk_head->x;
        temp->y = snk_head->y;

        /* 准备下一个 */
        snk_body = temp;
    }

    /*
     * 初始化食物
     */

    food = (food_entity*)malloc(sizeof(food_entity));

    food->x = random(0) % WIDTH_BLOCK_COUNT;
    food->y = random(0) % HIGHT_BLOCK_COUNT;
}

void snake_move(void)
{
    snk_body_entity* temp = snk_head;

    for (int i = snk_lenth - 1; i > 0; i--)
    {
        /* 跳转到最后 */
        for (int j = 0; j < i - 1; j++)
        {
            temp = temp->next_body;
        }

        /* 每后一个的运动都是前者位置 */
        temp->next_body->x = temp->x;
        temp->next_body->y = temp->y;

        temp = snk_head;
    }


    /* 蛇体移动方向 */
    switch (dir)
    {
    case DIR_DOWN:
        snk_head->y += 1;
        break;
    case DIR_UP:
        snk_head->y -= 1;
        break;
    case DIR_LEFT:
        snk_head->x -= 1;
        break;
    case DIR_RIGHT:
        snk_head->x += 1;
    }

    /* 超过边界返回 */
    if (snk_head->x >= WIDTH_BLOCK_COUNT)
    {
        snk_head->x = 0;
    }
    else if (snk_head->x < 0)
    {
        snk_head->x = WIDTH_BLOCK_COUNT;
    }
    else if (snk_head->y >= HIGHT_BLOCK_COUNT)
    {
        snk_head->y = 0;
    }
    else if (snk_head->y < 0)
    {
        snk_head->y = HIGHT_BLOCK_COUNT;
    }

    /* 碰到身体判断 */
    temp = snk_head->next_body;

    for (int i = 1; i < snk_lenth; i++)
    {
        if (temp->x == snk_head->x && temp->y == snk_head->y)
        {
            /* 释放食物内存 */
            free(food);
            /* 释放蛇内存 */
            snk_body_entity* temp = snk_head;
            for (int i = 0; i < snk_lenth; i++)
            {
                temp = snk_head;
                snk_head = temp->next_body;

                free(temp);
            }
            /* 将头指向空 */
            snk_head = NULL;
            /* 重新生成 */
            init_entity();

            /* 生成新食物 */
            food->x = random(0) % WIDTH_BLOCK_COUNT;
            food->y = random(0) % HIGHT_BLOCK_COUNT;

            break;
        }

        temp = temp->next_body;

    }
}

void snake_eat_food(void)
{
    /* 吃食物判定 生成新食物 */
    if (snk_head->x == food->x && snk_head->y == food->y)
    {
        /* 生成新食物 */
        food->x = random(0) % WIDTH_BLOCK_COUNT;
        food->y = random(0) % HIGHT_BLOCK_COUNT;

        /*
         * 生成新的身体
         */

         /* 最后生成新的蛇体 */
        snk_body->next_body = (snk_body_entity*)malloc(sizeof(snk_body_entity));

        snk_body->next_body->x = snk_body->x;
        snk_body->next_body->y = snk_body->y;
        /* 长度增加 */
        snk_lenth++;
        /* 为下一次增加准备 */
        snk_body = snk_body->next_body;
        /* 获得分数 */
        score += 100;
    }
}
